Channel 类
之前提到过在 NIO 中一个连接就是使用一个 channel 表示,也就是一个通道可以表示一个底层的文件描述符,比如硬件设备、文件、网络连接等。其实不止如此,除了了对应底层的文件描述符外,Java NIO 的通道还可以细化到不同的网络传输协议,对于不同的协议 Java NIO 都有不同的实现。
Channel 的主要类型
Channel 使用比较多的类型主要有四种
名称 | 说明 | 备注 |
---|---|---|
FileChannel | 文件通道,主要用于文件读写 | 只有阻塞模式,因为对于文件的读写不需要去轮询内核数据是否准备好 |
SocketChannel | 用于 socket 套接字 TCP 链接的数据读写 | 在客户端和服务端都存在 |
ServerSocketChannel | 服务器套接字通道,允许程序监听 TCP 连接请求,为每个监听到的请求创建一个 SocketChannel 通道 | 只存在于服务端 |
DatagramChannel | 用于 UDP 协议的数据读写 |
FileChannel 文件通道
可以通过文件的输入流、输出流获取FileChannel
通道,又或者通过RandomAccessFile文件随机访问类获取通道
在大部分的应用场景中,从通道读取数据都会调用通道的int read
写入到Buffer 中,也就是之前说过的ByteBufferbuf
方法,它将从通道的读取的数据写入到ByteBuffer
缓冲区中
通道读取数据对于Buffer缓冲区来说是写入数据,此时缓冲区处于写入模式
同样的大部分应用场景在往通道写入数据时是int write (ByteBufferbuf) 方法,此时缓冲区就是写入数据的来源。通过调用write()
方法从Buffer中读取数据,然后写入到通道中,返回值就是写入成功的字节数
在向通道中写入数据时要求缓冲区是可读的,需要缓冲区翻转成读模式。
channel.close
在将缓冲数据写入通道时,出于对性能考虑,操作系统不能每次都实时将数据写入磁盘。如果需要保证将缓冲数据立刻写入磁盘需要调用force()
方法强制刷新到磁盘
channel.force(true)
SocketChannel 套接字通道
在 NIO 中 SocketChannel 与 ServerSocketChannel 是相辅相成的,一个负责连接传输,一个负责连接监听。他们两个都支持阻塞和非阻塞两种模式。调用 socketChannel.configureBlocking(Boolean)
方法即可修改模式,考虑到效率方面,阻塞模式基本不会使用到。
获取 SocketChannel 通道
客户端获取通道
- 通过 SocketChannel 的 open 方法获得一个传输通道
- 将 socket 设置为非阻塞模式
- 对服务器 IP 和端口发起连接
服务器端获取套接字
通过调用服务器端 ServerSocketChannel 监听套接字的 accept() 方法,来获取新连接的套接字通道